#include <app.h>
#include <u_syscall.h>
#include <list.h>
#include <memory.h>

APP_INFO appInfo[MAX_APP_NUM] = {0};
U16 appNum = 0;

E_RET AppRegister(APP_FUNC pFunc, U08* stackAddr, U16 stackSize, U08* name, E_APP_PRI priority)
{
    if(appNum >= MAX_APP_NUM)
        return E_ERR;

    appInfo[appNum].pfunc = pFunc;
    appInfo[appNum].stackAddr = stackAddr;
    appInfo[appNum].stackSize = stackSize;
    appInfo[appNum].name = name;
    appInfo[appNum].priority = priority;
    appNum++;

    return E_OK;
}

/******************************************************************************
* 函数名称: static void TaskIdleFunc(void)
* 功能说明: 空闲任务
* 输入参数: 无
* 输出参数: 无
* 函数返回: 无
* 其它说明: 无
******************************************************************************/
#define IDLE_STACK_SIZE   512     
static U08 taskIdle_stack[IDLE_STACK_SIZE];    // 空闲任务私有栈
static void TaskIdleFunc(void)                 // 空闲任务执行函数
{
    static U32 count = 0;
    while(1)
    {
        ;
    }
}

U08 AppHeap[4096] = {0xff}; // 用户程序堆区

#define MAX 60              // 生产商品最大数量
U32 gPutNum = 0;            // 用于生产者计数
U32 gGetNum = MAX;          // 用于生产者计数
MUTEX* gMutex = NULL;       // 互斥锁


void Delay(U32 cnt)
{
    volatile U32 cnt_t = cnt; 
    while(cnt_t--);
}


static LIST gStore; // 仓库链表

typedef struct PRODUCT
{
    LIST_NODE node;
    U08 data;
} PRODUCT;

// 存
static void Store(U08 ch)
{
    PRODUCT* p = NULL;
    p = Malloc(sizeof(PRODUCT));
    if( NULL == p)
        return;
    p->data = ch;
    ListAddTail(&gStore, (LIST_NODE *)p);
}

// 取
static BOOL Fetch(char type, U08* ch)
{
    BOOL ret = FALSE;
    PRODUCT* p = NULL;
    LIST_NODE* pNode = NULL;
    LIST_FOR_EACH(&gStore, pNode)
    {
        p = (PRODUCT *)pNode;
        if('A' == type)
            ret = (p->data >= 'A') && (p->data <= 'Z');
        else if('B' == type)
            ret = (p->data >= 'a') && (p->data <= 'z');

        if(ret)
        {
            *ch = p->data;
            ListDelNode(pNode);
            Free(p);
            break;
        }
    }
    return ret;
}

static U08 PAStack[256] = {0xFF};
void ProducerA(void) // 生产者 A  
{
    U08 running = 0;
    U32 next = 0;
    gMutex = MutexCreat();
    while(1)
    {
        MutexLock(gMutex);
        if(running = (gPutNum < MAX))
        {
            // 生产商品，放入仓库
            U08 c = 'A' + next % 26;
            Store(c);
            SetCursorPos(next++, 8); // 打印到第 8 行
            print("%c", c);
            gPutNum++;
        }
        MutexUnLock(gMutex);
        if(running) 
            Delay(777777);
        else    
            break;
    }
}

static U08 PBStack[256] = {0xFF};
void ProducerB(void) // 生产者 B
{
    U08 running = 0;
    U32 next = 0;

    while(1)
    {
        MutexLock(gMutex);
        if(running = (gPutNum < MAX))
        {
            // 生产商品，放入仓库
            U08 c = 'a' + next % 26;
            Store(c);
            SetCursorPos(next++, 10); // 打印到第 10 行
            print("%c", c);
            gPutNum++;
        }
        MutexUnLock(gMutex);
        if(running) 
            Delay(888888);
        else    
            break;
    }
}

static U08 CAStack[256] = {0xFF};
void ConsumerA(void) // 消费者 A
{
    U08 running = 0;
    U32 next = 0;

    while(1)
    {
        MutexLock(gMutex);
        if(running = (gGetNum > 0))
        {
            // 商品出库，消耗库存
            U08 c = 0;
            if(Fetch('A', &c))
            {
                SetCursorPos(next++, 12); // 打印到第 12 行
                print("%c", c);
                gGetNum--; // 商品计数
            }
        }
        MutexUnLock(gMutex);
        if(running) 
            Delay(99999);
        else    
            break;
    }
}

static U08 CBStack[256] = {0xFF};
void ConsumerB(void) // 消费者 b
{
    U08 running = 0;
    U32 next = 0;

    while(1)
    {
        MutexLock(gMutex);
        if(running = (gGetNum > 0))
        {
            // 商品出库，消耗库存
            U08 c = 0;
            if(Fetch('B', &c))
            {
                SetCursorPos(next++, 14); // 打印到第 14 行
                print("%c", c);
                gGetNum--; // 商品计数
            }
        }
        MutexUnLock(gMutex);
        if(running) 
            Delay(999999);
        else    
            break;
    }
}



void AppInit(void)
{
    MemInit((U08 *)&AppHeap, 4096);
    ListInit(&gStore); // 初始化仓库

    AppRegister(ProducerA, PAStack, 256, "ProducerA", E_APP_PRI5);
    AppRegister(ProducerB, PBStack, 256, "ProducerB", E_APP_PRI5);
    AppRegister(ConsumerA, CAStack, 256, "ConsumerA", E_APP_PRI5);
    AppRegister(ConsumerB, CBStack, 256, "ConsumerB", E_APP_PRI5);

    // 把应用数据放入共享内存 0xA800 处
    *((volatile U32*)0xA800) = (U32)appInfo;
    *((volatile U32*)0xA804) = appNum;
    *((volatile U32*)0xA808) = (U32)taskIdle_stack;
    *((volatile U32*)0xA80C) = IDLE_STACK_SIZE;
    *((volatile U32*)0xA810) = (U32)TaskIdleFunc;
}
